package com.vdong.trade.trading.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.vdong.member.account.facade.AccountSysUserBankFacadeService;
import com.vdong.member.account.facade.AccountSystemUserFacadeService;
import com.vdong.trade.trading.common.constants.TradingConstants;
import com.vdong.trade.trading.common.contract.AbstractResponse;
import com.vdong.trade.trading.common.enums.AmountTypeEnum;
import com.vdong.trade.trading.common.enums.PayReturnCodeEnum;
import com.vdong.trade.trading.common.enums.TradeDealTypeEnum;
import com.vdong.trade.trading.common.enums.TransferTypeEnum;
import com.vdong.trade.trading.common.exception.ProcessException;
import com.vdong.trade.trading.common.exception.ServiceException;
import com.vdong.trade.trading.common.utils.DateUtil;
import com.vdong.trade.trading.entity.dto.*;
import com.vdong.trade.trading.entity.dto.param.AmountDataDTO;
import com.vdong.trade.trading.entity.dto.param.AmountTradingParamDTO;
import com.vdong.trade.trading.entity.dto.param.PaymentRequestDTO;
import com.vdong.trade.trading.entity.dto.param.WithdrawDTO;
import com.vdong.trade.trading.entity.dto.result.AccountSysUserBankDTO;
import com.vdong.trade.trading.entity.dto.result.AmountResultDTO;
import com.vdong.trade.trading.entity.dto.result.MoneyAndCountResultDTO;
import com.vdong.trade.trading.entity.dto.result.PaymentResponseDTO;
import com.vdong.trade.trading.entity.po.SettlementTotalParamDTO;
import com.vdong.trade.trading.entity.po.WithdrawParamDTO;
import com.vdong.trade.trading.entity.mo.*;
import com.vdong.trade.trading.entity.vo.WithdrawConfigVO;
import com.vdong.trade.trading.facade.enums.*;
import com.vdong.trade.trading.respository.WithdrawMOMapper;
import com.vdong.trade.trading.service.AmountService;
import com.vdong.trade.trading.service.TradingService;
import com.vdong.trade.trading.service.TransactionPayService;
import com.vdong.trade.trading.service.WithdrawService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.lamb.framework.common.remote.FacadeResult;
import org.lamb.framework.common.userDTO.AccountSystemUserInfoDTO;
import org.lamb.framework.common.userDTO.PeddleUserDTO;
import org.lamb.framework.common.util.CopyUtil;
import org.lamb.framework.common.util.FacadeResultUtils;
import org.lamb.framework.common.util.StringUtil;
import org.lamb.framework.core.security.LambPrincipalFactoryContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Optional;

import static com.vdong.trade.trading.common.enums.ProcessExceptionEnum.EB00000005;

/**
 * @author zhoulongbiao
 * @Date 2018/12/10 15:54
 */
@Service
@Slf4j
public class WithdrawServiceImpl implements WithdrawService {

    @Resource
    private WithdrawMOMapper withdrawMOMapper;

    @Autowired
    private AmountService amountService;

    @Autowired
    private TradeDynamicPropertyService tradeDynamicPropertyService;

    @Autowired
    private TransactionPayService transactionPayService;

    @Autowired
    private TradingService tradingService;

    @Reference
    private AccountSysUserBankFacadeService accountSysUserBankFacadeService;

    @Reference
    private AccountSystemUserFacadeService accountSystemUserFacadeService;

    @Override
    public PageInfo<WithdrawRecordListDTO> withdrawRecordList(WithdrawParamDTO param) {
        log.info("withdrawRecordList,入参为:[{}]", JSON.toJSONString(param));
        PageInfo<WithdrawRecordListDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(withdrawMOMapper.selectWithdrawRecordList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), WithdrawRecordListDTO.class);
                });
        return resultPageInfo;
    }

    @Override
    public WithdrawDetailDTO withdrawDetail(WithdrawParamDTO param) {
        log.info("withdrawDetail,入参为:[{}]", JSON.toJSONString(param));
        return CopyUtil.copyObject(Optional.ofNullable(withdrawMOMapper.selectWithdrawDetail(param))
                .orElseThrow(() -> new ProcessException(EB00000005)), new WithdrawDetailDTO());
    }

    @Override
    public PageInfo<WithdrawApplyListDTO> withdrawApplyList(WithdrawParamDTO param) {
        log.info("withdrawApplyList,入参为:[{}]", JSON.toJSONString(param));
        PageInfo<WithdrawApplyListDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(withdrawMOMapper.selectWithdrawApplyList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), WithdrawApplyListDTO.class);
                });
        return resultPageInfo;
    }

    @Override
    public WithdrawApplyDetailDTO withdrawApplyDetail(WithdrawParamDTO param) {
        log.info("withdrawApplyDetail,入参为:[{}]", JSON.toJSONString(param));
        return CopyUtil.copyObject(Optional.ofNullable(withdrawMOMapper.selectWithdrawApplyDetail(param))
                .orElseThrow(() -> new ProcessException(EB00000005)), new WithdrawApplyDetailDTO());
    }

    @Override
    public PageInfo<TransferApplyListDTO> transferApplyList(SettlementTotalParamDTO param) {
        log.info("transferApplyList,入参为:[{}]", JSON.toJSONString(param));
        PageInfo<TransferApplyListDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(withdrawMOMapper.transferApplyList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), TransferApplyListDTO.class);
                });
        return resultPageInfo;
    }

    @Override
    public TransferConfirmOrRefuseMO transferConfirmOrRefuse(SettlementTotalParamDTO param) {
        log.info("transferConfirmOrRefuse,入参为:[{}]", JSON.toJSONString(param));
        if (param.getType().compareTo(TransferTypeEnum.CONFIRM.getValue().toString()) == 0) {
            int row = withdrawMOMapper.updateWithdrawById(WithdrawMO.builder()
                    .withdrawStatus(WithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus()).id(Long.valueOf(param.getTransferId())).build());
            if (row < 1) return TransferConfirmOrRefuseMO.builder().flag(false).build();
            return TransferConfirmOrRefuseMO.builder().flag(true).build();
        } else {
            int row = withdrawMOMapper.updateWithdrawById(WithdrawMO.builder().id(Long.valueOf(param.getTransferId()))
                    .reason(param.getReason()).withdrawStatus(WithdrawStatusEnum.WITHDRAW_FAIL.getStatus()).build());
            if (row < 1) return TransferConfirmOrRefuseMO.builder().flag(false).build();
            return TransferConfirmOrRefuseMO.builder().flag(true).build();
        }
    }

    @Override
    public PageInfo<TransferRecordListDTO> transferRecordList(SettlementTotalParamDTO param) {
        log.info("transferRecordList,入参为:[{}]", JSON.toJSONString(param));
        PageInfo<TransferRecordListDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(withdrawMOMapper.transferRecordList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), TransferRecordListDTO.class);
                });
        return resultPageInfo;
    }

    @Override
    public TransferRecordDetailDTO transferRecordDetail(SettlementTotalParamDTO param) {
        log.info("transferRecordDetail,入参为:[{}]", JSON.toJSONString(param));
        return CopyUtil.copyObject(Optional.ofNullable(withdrawMOMapper.transferRecordDetail(param))
                .orElseThrow(() -> new ProcessException(EB00000005)), new TransferRecordDetailDTO());
    }

    /**
     * 备注:无论成功失败,都需要记录提现操作记录
     * 1:新增提现记录
     * <p>
     * 2:减少可用余额 增加冻结金额
     * 3:调用支付接口
     * 成功:则减少冻结金额,并插入资金交易流水,提现订单状态更新为成功
     * 失败:则回滚金额操作,提现订单状态更新为失败
     * 第三方支付异常:不需要回滚金额,提现订单状态更新为第三方支付异常
     * 4:返回提现成功或失败
     *
     * @param withdrawDTO
     * @return
     */
    @Override
    public FacadeResult<String> userWithdraw(WithdrawDTO withdrawDTO) {
        log.info("userWithdraw业务接口请求参数:[{}]", JSON.toJSONString(withdrawDTO));

        // 获取当前推客用户缓存信息
        PeddleUserDTO peddleUser = LambPrincipalFactoryContainer.getPeddleUser();
        if (peddleUser == null) {
            log.error("推客提现获取用户缓存信息失败!");
            return FacadeResult.buildFail("提现失败!");
        }

        if (StringUtil.hasBlank(peddleUser.getId())) {
            log.error("推客提现获取用户缓存userId为空!");
            return FacadeResult.buildFail("提现失败!");
        }
        withdrawDTO.setUserName(peddleUser.getNickName());
        withdrawDTO.setUserId(peddleUser.getId());

        // 新增提现记录
        Long withdrawId = this.insertWithdrawByParam(withdrawDTO, null, UserTypeEnum.PUSHER);

        WithdrawMO updateWithdrawMO = new WithdrawMO();
        updateWithdrawMO.setId(withdrawId);
        updateWithdrawMO.setUpdateTime(new Date());

        // 调用支付接口 result为支付接口返回
        BigDecimal withdrawMoney = new BigDecimal(withdrawDTO.getAmount());
        FacadeResult<AbstractResponse> result = this.withdrawToTransactionPay(withdrawDTO, withdrawId);

        log.info("userWithdraw支付接口返回result ===>{}", JSON.toJSONString(result));
        PaymentResponseDTO paymentResponseDTO = null;
        if (result.isSuccess()) {
            paymentResponseDTO = (PaymentResponseDTO) result.getData();
            updateWithdrawMO.setTradingNo(paymentResponseDTO.getPaymentNo());
            updateWithdrawMO.setWithdrawStatus(WithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus());
        } else {
            updateWithdrawMO.setReason(result.getErrorMsg());
            // 第三方支付异常
            if (PayReturnCodeEnum.THIRD_SYSTEM_ERROR.getCode().equals(result.getErrorCode()) ||
                    PayReturnCodeEnum.SYSTEM_ERROR.getCode().equals(result.getErrorCode())) {
                updateWithdrawMO.setWithdrawStatus(WithdrawStatusEnum.WITHDRAW_SYSTEM_ERROR.getStatus());
            } else {
                updateWithdrawMO.setWithdrawStatus(WithdrawStatusEnum.WITHDRAW_FAIL.getStatus());
            }
        }
        int count = withdrawMOMapper.updateWithdrawById(updateWithdrawMO);
        if (count < 1) {
            log.error("用户userId=[{}]申请提现时,支付结果为:[{}],更新提现订单失败!", withdrawDTO.getUserId()
                    , WithdrawStatusEnum.getEnumValue(updateWithdrawMO.getWithdrawStatus()));

        }

        if (!result.isSuccess()) {
            if (PayReturnCodeEnum.THIRD_SYSTEM_ERROR.getCode().equals(result.getErrorCode()) ||
                    PayReturnCodeEnum.SYSTEM_ERROR.getCode().equals(result.getErrorCode())) {
                // 第三方支付异常,无需做回滚操作,提现处理中/支付接口异常
                return FacadeResult.buildFail(PayReturnCodeEnum.THIRD_SYSTEM_ERROR.getMsg());
            } else {
                // 提现失败,需要做资金回滚操作,返回提现失败
                AmountDataDTO dataDTO = new AmountDataDTO();
                dataDTO.setUserId(withdrawDTO.getUserId());
                dataDTO.setUserType(UserTypeEnum.PUSHER.getValue().toString());
                dataDTO.setUpdateTime(new Date());
                dataDTO.setBalance(withdrawMoney);
                dataDTO.setFrozenAmount(withdrawMoney.multiply(TradingConstants.MINUS_BIGDECIMAL));
                dataDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_UNFREEZE.getType());
                amountService.updateAmountByParam(dataDTO);
                return FacadeResult.buildFail("提现失败");
            }
        }

        // todo 减少冻结金额,并插入资金交易流水,提现订单状态更新为成功
        AmountTradingParamDTO amountTradingParamDTO = new AmountTradingParamDTO();
        amountTradingParamDTO.setUserId(withdrawDTO.getUserId());
        amountTradingParamDTO.setUserType(UserTypeEnum.PUSHER.getValue().toString());
        amountTradingParamDTO.setUpdateTime(new Date());
        amountTradingParamDTO.setFrozenAmount(withdrawMoney.multiply(TradingConstants.MINUS_BIGDECIMAL));
        amountTradingParamDTO.setTotalWithdraw(withdrawMoney);

        amountTradingParamDTO.setName(withdrawDTO.getUserName() == null ? StringUtils.EMPTY : withdrawDTO.getUserName());
        amountTradingParamDTO.setTradeType(TradeTypeEnum.ACCOUNT_OUT.getValue().toString());
        amountTradingParamDTO.setPayType(PayTypeEnum.WECHAT_PAY.getValue().toString());
        amountTradingParamDTO.setStatus(StatusEnum.STATUS_NO.getValue().toString());
        amountTradingParamDTO.setSettlementStatus(SettlementStatusEnum.ALREADY_SETTLEMENT.getValue().toString());
        amountTradingParamDTO.setMoney(withdrawMoney);
        amountTradingParamDTO.setWechatDataId(paymentResponseDTO.getPayId());
        amountTradingParamDTO.setDealType(TradeDealTypeEnum.WITHDRAW_SUCCESS.getType());
        amountTradingParamDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_SUCCESS.getType());
        Optional<String> trading = amountService.amountTrading(amountTradingParamDTO, true);

        // 更新账户失败
        if (trading.isPresent()) {
            log.error("用户userId=[{}] ==> 提现操作时,第三方支付成功,减少冻结金额失败原因:[{}]", withdrawDTO.getUserId(), trading.get());
        }

        return FacadeResult.buildSucc();
    }

    @Override
    public FacadeResult<String> merchantWithdraw(WithdrawDTO withdrawDTO) {
        log.info("merchantWithdraw请求参数:[{}]", JSON.toJSONString(withdrawDTO));

        // 获取当前商户用户缓存信息
        AccountSystemUserInfoDTO accountSystemUser = LambPrincipalFactoryContainer.getAccountSystemUser();
        if (accountSystemUser == null) {
            log.error("商户提现获取用户缓存信息失败!");
            return FacadeResult.buildFail("提现失败!");
        }

        if (StringUtil.hasBlank(accountSystemUser.getSysUserId())) {
            log.error("推客提现获取用户缓存userId为空!");
            return FacadeResult.buildFail("提现失败!");
        }

        withdrawDTO.setUserId(Long.valueOf(accountSystemUser.getSysUserId()));

        // 商户提现金额
        BigDecimal amount = new BigDecimal(withdrawDTO.getAmount());
        // 判断提现金额
        BigDecimal minAmount = new BigDecimal(tradeDynamicPropertyService.getMerchantWithdrawMinAmount());
        if (amount.compareTo(minAmount) < 0) {
            return FacadeResult.buildFail("提现金额小于最小提现金额!");
        }

        // 获取当月提现次数
        Integer count = this.buildWithdrawAuditMO(withdrawDTO);
        // 每月可提现次数
        Integer totalCount = Integer.valueOf(tradeDynamicPropertyService.getMerchantWithdrawCount());
        if (count >= totalCount) {
            return FacadeResult.buildFail("可提现次数不足!");
        }

        // 获取商户银行卡数据
        AccountSysUserBankDTO bankDTO = null;
        try {
            HashMap<String, Object> hashMap = new HashMap<>(4);
            hashMap.put("id", withdrawDTO.getBankId());
            String bankDetail = accountSysUserBankFacadeService.getAccountSysUserBankDetail(JSON.toJSONString(hashMap));

            FacadeResult<AccountSysUserBankDTO> result =
                    FacadeResultUtils.stringToFacadeBean(bankDetail, AccountSysUserBankDTO.class);
            if (result.isSuccess()) {
                if (result.getData() == null) {
                    return FacadeResult.buildFail("用户银行卡信息为空!");
                }
            } else {
                return FacadeResult.buildFail("获取用户银行卡信息失败!");
            }
            bankDTO = result.getData();
        } catch (Exception e) {
            return FacadeResult.buildFail("获取用户银行卡信息异常!");
        }


        if (!StringUtil.hasBlank(accountSystemUser.getPlatformInsideId())) {
            String s = "ZZ" + accountSystemUser.getPlatformInsideId() + DateUtil.getDateTimeStr(DateUtil.yyyyMMddHHmm);
            withdrawDTO.setTradingNo(s);
        }

        // 新增提现记录
        Long withdrawId = this.insertWithdrawByParam(withdrawDTO, bankDTO, UserTypeEnum.MERCHANT);

        //冻结账户金额
        AmountDataDTO amountDataDTO = new AmountDataDTO();
        amountDataDTO.setUserId(withdrawDTO.getUserId());
        amountDataDTO.setUserType(UserTypeEnum.MERCHANT.getValue().toString());
        amountDataDTO.setUpdateTime(new Date());
        amountDataDTO.setBalance(amount.multiply(TradingConstants.MINUS_BIGDECIMAL));
        amountDataDTO.setFrozenAmount(amount);
        amountDataDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_FREEZE.getType());
        Optional<String> optional = amountService.updateAmountByParam(amountDataDTO);
        // 更新账户失败
        if (optional.isPresent()) {
            log.error("用户userId=[{}],userType=[{}] ==> 提现操作时,减少可用余额,增加冻结失败原因:[{}]",
                    withdrawDTO.getUserId(), UserTypeEnum.MERCHANT.getState(), optional.get());
            return FacadeResult.buildFail("提现失败!");
        }
        return FacadeResult.buildSucc();
    }

    private Integer buildWithdrawAuditMO(WithdrawDTO withdrawDTO) {
        WithdrawAuditMO withdrawAuditMO = new WithdrawAuditMO();
        withdrawAuditMO.setUserId(withdrawDTO.getUserId());
        if (StringUtil.hasBlank(withdrawDTO.getUserType())) {
            withdrawAuditMO.setUserType(UserTypeEnum.MERCHANT.getValue().toString());
        } else {
            withdrawAuditMO.setUserType(withdrawDTO.getUserType());
        }
        withdrawAuditMO.setStartTime(DateUtil.getMonthFirstDate(0));
        withdrawAuditMO.setEndTime(DateUtil.getMonthFirstDate(1));
        return withdrawMOMapper.selectWithdrawCount(withdrawAuditMO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FacadeResult<String> withdrawAudit(WithdrawDTO withdrawDTO) {
        log.info("商户提现审核接口请求参数:[{}]", JSON.toJSONString(withdrawDTO));
        WithdrawMO withdrawMO = withdrawMOMapper.selectWithdrawById(withdrawDTO.getId());
        if (withdrawMO == null) {
            return FacadeResult.buildFail("提现记录不存在!");
        }
        if (!WithdrawStatusEnum.WITHDRAW_INIT.getStatus().equals(withdrawMO.getWithdrawStatus())) {
            return FacadeResult.buildFail("提现订单已审核!");
        }
        // 更新提现订单状态
        WithdrawAuditMO auditMO = new WithdrawAuditMO();
        auditMO.setId(withdrawMO.getId());
        auditMO.setAuditBeforeStatus(WithdrawStatusEnum.WITHDRAW_INIT.getStatus());
        auditMO.setAuditAfterStatus(withdrawDTO.getWithdrawStatus());
        auditMO.setUpdateTime(new Date());
        auditMO.setCompleteTime(new Date());
        if (!StringUtil.hasBlank(withdrawDTO.getReason())) {
            auditMO.setReason(withdrawDTO.getReason());
        }
        int count = withdrawMOMapper.updateWithdrawByParam(auditMO);

        if (count < 1) {
            return FacadeResult.buildFail("审核失败!");
        }

        //TODO 审核成功后,修改用户账户资金信息
        AmountTradingParamDTO paramDTO = new AmountTradingParamDTO();
        paramDTO.setUserId(withdrawMO.getUserId());
        paramDTO.setUserType(UserTypeEnum.MERCHANT.getValue().toString());
        paramDTO.setUpdateTime(new Date());
        Boolean flag = true;

        //  成功,需获取用户的name
        if (WithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus().equals(withdrawDTO.getWithdrawStatus())) {
            paramDTO.setFrozenAmount(withdrawMO.getMoney().multiply(TradingConstants.MINUS_BIGDECIMAL));
            paramDTO.setTotalWithdraw(withdrawMO.getMoney());
            paramDTO.setMoney(withdrawMO.getMoney());
            paramDTO.setTradeType(TradeTypeEnum.ACCOUNT_OUT.getValue().toString());
            paramDTO.setPayType(PayTypeEnum.WECHAT_PAY.getValue().toString());
            paramDTO.setStatus(StatusEnum.STATUS_NO.getValue().toString());
            paramDTO.setSettlementStatus(SettlementStatusEnum.ALREADY_SETTLEMENT.getValue().toString());
            paramDTO.setDealType(TradeDealTypeEnum.WITHDRAW_SUCCESS.getType());
            paramDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_SUCCESS.getType());
            // 调用服务获取商户姓名
            HashMap<String, Object> param = new HashMap<>(4);
            param.put("sysUserId", withdrawMO.getUserId());
            param.put("userType", withdrawMO.getUserType());
            String result = accountSystemUserFacadeService.
                    getAccountSystemPeddleUserInfoBySysUserId(JSON.toJSONString(param));
            FacadeResult<AccountSystemUserInfoDTO> userInfoDTO =
                    FacadeResultUtils.stringToFacadeBean(result, AccountSystemUserInfoDTO.class);
            if (userInfoDTO.isSuccess()) {
                paramDTO.setName(userInfoDTO.getData().getSysUserName());
            } else {
                paramDTO.setName(StringUtils.EMPTY);
            }
        } else {
            // 失败
            flag = false;
            paramDTO.setBalance(withdrawMO.getMoney());
            paramDTO.setFrozenAmount(withdrawMO.getMoney().multiply(TradingConstants.MINUS_BIGDECIMAL));
            paramDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_UNFREEZE.getType());
        }

        Optional<String> optional = amountService.amountTrading(paramDTO, flag);
        if (optional.isPresent()) {
            throw new ServiceException("审核异常!");
        }
        return FacadeResult.buildSucc();
    }

    @Override
    public MoneyAndCountResultDTO moneyAndCount(SettlementTotalParamDTO param) {
        log.info("moneyAndCount,入参为:[{}]", JSON.toJSONString(param));
        MoneyAndCountMO moneyAndCountMO = withdrawMOMapper.moneyAndCount(param);

        MoneyAndCountResultDTO moneyAndCountResultDTO = new MoneyAndCountResultDTO();

        if (StringUtil.hasBlank(moneyAndCountMO.getTransferMoney())) {
            moneyAndCountResultDTO.setTransferMoney("0");
        } else {
            moneyAndCountResultDTO.setTransferMoney(moneyAndCountMO.getTransferMoney());
        }

        moneyAndCountResultDTO.setTransferCount(moneyAndCountMO.getTransferCount());

        return moneyAndCountResultDTO;
    }

    @Override
    public WithdrawConfigVO withdrawConfig(WithdrawDTO withdrawDTO) {
        // 查询用户当月提现次数
        String totalcount = tradeDynamicPropertyService.getMerchantWithdrawCount();
        String amount = tradeDynamicPropertyService.getMerchantWithdrawMinAmount();

        WithdrawConfigVO withdrawConfigVO = new WithdrawConfigVO();
        withdrawConfigVO.setTotalCount(totalcount);
        withdrawConfigVO.setMinAmount(amount);

        Integer count = this.buildWithdrawAuditMO(withdrawDTO);
        withdrawConfigVO.setCount(String.valueOf((Integer.valueOf(totalcount) - count)));
        return withdrawConfigVO;
    }

    private Long insertWithdrawByParam(WithdrawDTO withdrawDTO, AccountSysUserBankDTO bankDTO,
                                       UserTypeEnum userTypeEnum) throws ServiceException {
        // 获取用户资金信息
        AmountResultDTO amountResultDTO = amountService.selectAmountMOByUserId(
                withdrawDTO.getUserId(), userTypeEnum.getValue().toString());
        if (amountResultDTO == null) {
            log.error("获取用户userId=[{}],userType=[{}] ==> 资金账户信息失败!", withdrawDTO.getUserId(),
                    userTypeEnum.getState());
            throw new ServiceException("获取账户资金信息失败!");
        }

        //todo 判断提现金额
        if (new BigDecimal(withdrawDTO.getAmount()).compareTo(amountResultDTO.getBalance()) > 0) {
            log.error("获取用户userId=[{}],userType=[{}] ==> 可提现金额不足!", withdrawDTO.getUserId(),
                    userTypeEnum.getState());
            throw new ServiceException("可提金额不足!");
        }

        WithdrawMO withdrawMO = new WithdrawMO();
        withdrawMO.setUserId(withdrawDTO.getUserId());
        withdrawMO.setUserType(userTypeEnum.getValue().toString());
        withdrawMO.setMoney(new BigDecimal(withdrawDTO.getAmount()));
        withdrawMO.setStatus(StatusEnum.STATUS_NO.getValue().toString());
        withdrawMO.setCreateTime(new Date());
        withdrawMO.setUpdateTime(new Date());
        withdrawMO.setSurplusMoney(amountResultDTO.getBalance().subtract(new BigDecimal(withdrawDTO.getAmount())));
        withdrawMO.setCompleteTime(new Date());
        if (StringUtil.hasBlank(withdrawDTO.getTradingNo())) {
            withdrawMO.setTradingNo(StringUtils.EMPTY);
        } else {
            withdrawMO.setTradingNo(withdrawDTO.getTradingNo());
        }
        withdrawMO.setOrderNo(StringUtils.EMPTY);
        withdrawMO.setReason(StringUtils.EMPTY);
        withdrawMO.setCompany(withdrawDTO.getUserName() == null ? TradingConstants.COMPANY_NAME : withdrawDTO.getUserName());
        withdrawMO.setWithdrawStatus(WithdrawStatusEnum.WITHDRAW_INIT.getStatus());

        if (StringUtil.hasBlank(bankDTO)) {
            withdrawMO.setBank(StringUtils.EMPTY);
            withdrawMO.setBankAccount(StringUtils.EMPTY);
        } else {
            withdrawMO.setBank(bankDTO.getBank());
            withdrawMO.setBankAccount(bankDTO.getBankNo());
            withdrawMO.setCompany(bankDTO.getCompany());
        }
        withdrawMOMapper.insertWithdraw(withdrawMO);
        return withdrawMO.getId();
    }


    /**
     * 2:减少可用余额 增加冻结金额
     * 3:调用支付接口
     * 成功:则减少冻结金额,并插入资金交易流水,提现订单状态更新为成功
     * 失败:则回滚金额操作,提现订单状态更新为失败
     * 第三方支付异常:不需要回滚金额,提现订单状态更新为第三方支付异常
     * 4:返回提现成功或失败
     *
     * @param param 1:成功 2:失败 3:第三方异常
     * @return
     */
    //@Transactional(rollbackFor = Exception.class)
    public FacadeResult<AbstractResponse> withdrawToTransactionPay(WithdrawDTO param, Long withdrawMOId) throws ServiceException {
        // TODO 2:调用交易服务减少可用余额,增加冻结用户提现金额
        BigDecimal amount = new BigDecimal(param.getAmount());
        AmountDataDTO amountDataDTO = new AmountDataDTO();
        amountDataDTO.setUserId(param.getUserId());
        amountDataDTO.setUserType(UserTypeEnum.PUSHER.getValue().toString());
        amountDataDTO.setUpdateTime(new Date());
        amountDataDTO.setBalance(amount.multiply(TradingConstants.MINUS_BIGDECIMAL));
        amountDataDTO.setFrozenAmount(amount);
        amountDataDTO.setAmountType(AmountTypeEnum.WITHDRAWAL_FREEZE.getType());
        Optional<String> optional = amountService.updateAmountByParam(amountDataDTO);
        // 更新账户失败
        if (optional.isPresent()) {
            log.error("用户userId=[{}] ==> 提现操作时,减少可用余额,增加冻结失败原因:[{}]", param.getUserId(), optional.get());
            throw new ServiceException("冻结提现金额失败!");
        }

        //TODO  3:调用支付接口
        PaymentRequestDTO requestDTO = new PaymentRequestDTO();
        // TODO 将金额转换为分
        //requestDTO.setTotalFee(amount.longValue() * 100);
        requestDTO.setTotalFee(30L);
        requestDTO.setSpbillCreateIp(param.getIp());
        requestDTO.setPayChannel(PayChannelEnum.WECHAT_PAY.getCode());
        requestDTO.setOrderType(WechatPayEnums.OrderTypeEnum.MERCHANT_PAY.getType());
        requestDTO.setOpenid(param.getOpenid());
        requestDTO.setDesc(TradingConstants.DESC);
        requestDTO.setOrderNo(withdrawMOId.toString());

        // 调用第三方支付接口
        FacadeResult<AbstractResponse> result = transactionPayService.execPay(requestDTO);
        log.info("用户userId=[{}]提现,第三方支付返回参数:[{}]", param.getUserId(), JSON.toJSONString(result));
        /*if (!result.isSuccess()) {
            if (PayReturnCodeEnum.THIRD_SYSTEM_ERROR.getCode().equals(result.getErrorCode()) ||
                    PayReturnCodeEnum.SYSTEM_ERROR.getCode().equals(result.getErrorCode())) {
                // 第三方支付异常,无需做回滚操作,提现处理中/支付接口异常
                return result;
            } else {
                // 提现失败,需要做资金回滚操作,返回提现失败
                AmountDataDTO dataDTO = new AmountDataDTO();
                dataDTO.setUserId(param.getUserId());
                dataDTO.setUserType(UserTypeEnum.PUSHER.getValue().toString());
                dataDTO.setUpdateTime(new Date());
                dataDTO.setBalance(amount);
                dataDTO.setFrozenAmount(amount.multiply(TradingConstants.MINUS_BIGDECIMAL));
                amountService.updateAmountByParam(dataDTO);
                return result;
            }

        }*/

        /*PaymentResponseDTO paymentResponseDTO = (PaymentResponseDTO) result.getData();

        // todo 减少冻结金额,并插入资金交易流水,提现订单状态更新为成功
        AmountTradingParamDTO amountTradingParamDTO = new AmountTradingParamDTO();
        amountTradingParamDTO.setUserId(param.getUserId());
        amountTradingParamDTO.setUserType(UserTypeEnum.PUSHER.getValue().toString());
        amountTradingParamDTO.setUpdateTime(new Date());
        amountTradingParamDTO.setFrozenAmount(amount.multiply(TradingConstants.MINUS_BIGDECIMAL));
        amountTradingParamDTO.setTotalWithdraw(amount);

        amountTradingParamDTO.setName(param.getUserName() == null ? StringUtils.EMPTY : param.getUserName());
        amountTradingParamDTO.setTradeType(TradeTypeEnum.ACCOUNT_OUT.getValue().toString());
        amountTradingParamDTO.setPayType(PayTypeEnum.WECHAT_PAY.getValue().toString());
        amountTradingParamDTO.setStatus(StatusEnum.STATUS_NO.getValue().toString());
        amountTradingParamDTO.setSettlementStatus(SettlementStatusEnum.ALREADY_SETTLEMENT.getValue().toString());
        amountTradingParamDTO.setMoney(amount);
        amountTradingParamDTO.setWechatDataId(paymentResponseDTO.getPayId());
        amountTradingParamDTO.setDealType(TradeDealTypeEnum.WITHDRAW_SUCCESS.getType());
        Optional<String> trading = amountService.amountTrading(amountTradingParamDTO, true);

        // 更新账户失败
        if (trading.isPresent()) {
            log.error("用户userId=[{}] ==> 提现操作时,第三方支付成功,减少冻结金额失败原因:[{}]", param.getUserId(), trading.get());
        }*/

        return result;
    }

    public static void main(String[] args) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = DateUtil.getMonthFirstDate(0);
        System.out.println(format.format(date));


        Date monthFirstDate = DateUtil.getMonthFirstDate(1);
        String first = format.format(monthFirstDate.getTime());
        System.out.println(first);
    }
}
